package it.gtd.swimpool.model.business;

import com.google.common.annotations.VisibleForTesting;
import com.mysema.query.BooleanBuilder;
import com.mysema.query.jpa.impl.JPAQuery;
import it.gtd.swimpool.model.entity.Message;
import it.gtd.swimpool.model.entity.QMessage;
import it.gtd.swimpool.model.entity.User;
import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import org.jetbrains.annotations.Nullable;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.Date;
import java.util.List;

import static com.google.common.base.Preconditions.*;

@Stateless
@LocalBean
public class CommunicationManager {
    private static final String EMAIL_FROM = "totem.swimpool@gmail.com";
    private static final String EMAIL_PASSWORD = "swimpool4ever";

    @PersistenceContext
    private EntityManager entityManager;

    public CommunicationManager() {}

    @VisibleForTesting
    public CommunicationManager(
            EntityManager entityManager
    ) {
        this();
        this.entityManager = entityManager;
    }

    public void sendEmail(User user, String subject, String messageText) {
        checkNotNull(user, "user can't be null");
        checkNotNull(subject, "subject can't be null");
        checkNotNull(messageText, "messageText can't be null");
        checkArgument(!subject.isEmpty(), "subject can't be empty");
        checkArgument(!messageText.isEmpty(), "message can't be empty");

        SimpleEmail email = new SimpleEmail();
        try {
            if (user.getName() != null && !user.getName().isEmpty()) {
                email.addTo(user.getEmail(), user.getName());
            } else {
                email.addTo(user.getEmail());
            }

            setupGmailEmail(email);
            email.setSubject(subject);
            email.setMsg(messageText);
            email.send();
        } catch (EmailException ex) {
            checkState(false, ex.getMessage());
        }
    }

    public void sendMessage(User sender, User recipient, String messageText) {
        checkNotNull(sender, "sender can't be null");
        checkNotNull(recipient, "recipient can't be null");
        checkNotNull(messageText, "messageText can't be null");
        checkArgument(sender != recipient, "cannot send a message to yourself");
        checkArgument(!messageText.isEmpty(), "Message can't be empty");
        checkArgument(entityManager.contains(sender), "Sender is not a managed entity");
        checkArgument(entityManager.contains(recipient), "Receiver is not a managed entity");

        Message message = new Message(messageText, sender, recipient);
        entityManager.persist(message);

        checkState(entityManager.contains(message));
    }

    public List<Message> getMessages(@Nullable User receiver, @Nullable User sender, @Nullable Date since, @Nullable Date until) {
        JPAQuery query = new JPAQuery(entityManager);
        QMessage message = QMessage.message;
        query = query.from(message);

        BooleanBuilder expression = new BooleanBuilder();

        if (null != receiver) {
            expression.and(message.composed().receiver().eq(receiver));
        }

        if (null != sender) {
            expression.and(message.composed().sender().eq(sender));
        }

        if (null != since) {
            expression.and(message.composed().date.gt(since));
        }

        if (null != until) {
            expression.and(message.composed().date.lt(until));
        }


        return query.where(expression).orderBy(message.composed().date.desc()).list(message);
    }

    private void setupGmailEmail(Email email) throws EmailException {
        email.setSmtpPort(587);
        email.setAuthenticator(new DefaultAuthenticator(EMAIL_FROM, EMAIL_PASSWORD));
        email.setDebug(true);
        email.setHostName("smtp.gmail.com");
        email.getMailSession().getProperties().put("mail.smtps.auth", "true");
        email.getMailSession().getProperties().put("mail.debug", "true");
        email.getMailSession().getProperties().put("mail.smtps.port", "587");
        email.getMailSession().getProperties().put("mail.smtps.socketFactory.port", "587");
        email.getMailSession().getProperties().put("mail.smtps.socketFactory.class",   "javax.net.ssl.SSLSocketFactory");
        email.getMailSession().getProperties().put("mail.smtps.socketFactory.fallback", "false");
        email.getMailSession().getProperties().put("mail.smtp.starttls.enable", "true");
        email.setFrom(EMAIL_FROM, "SwimPool Support");
        email.setTLS(true);
    }
}
